package com.aaa.service.impl;

import com.aaa.dao.RedisStockDao;
import com.aaa.entity.RedisStock;
import com.aaa.service.RedisStockStoryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * -*- coding:utf-8 -*-
 *
 * @author 太阳偷渡青山
 * @software IntelliJ IDEA
 * @date 2022/12/08 13:25
 * @Description
 */
@Service()
public class RedisStockStoryServiceImpl extends ServiceImpl<RedisStockDao, RedisStock> implements RedisStockStoryService {
    @Resource
    private RedisStockDao redisStockDao;

    /**
     * 1 非原子操作 加锁操作和后面的设置超时时间是分开的，并非原子操作。
     *
     * 假如加锁成功，但是设置超时时间失败了，该lockKey就变成永不失效。
     * 假如在高并发场景中，有大量的lockKey加锁成功了，但不会失效，有可能直接导致redis内存空间不足。
     * @param id id
     * @return {@link String}
     */
    @Override
    public String decrRedisNonatomic(Integer id) {
        Jedis jedis = new Jedis("127.0.0.1",6379);
        Long val = jedis.setnx("lockKey::"+id, "val");
        if(val == 1){
            jedis.expire("lockKey::"+id,1L);
            long threadId = Thread.currentThread().getId();
            RedisStock stock = redisStockDao.selectById(id);
            if(stock.getNum() > 0){
                stock.setNum(stock.getNum() - 1);
                redisStockDao.updateById(stock);
                System.out.println("线程：" + threadId + ",商品编号："+id + ",商品剩余："+ stock.getNum() + "个！");
                return "线程：" + threadId + ",商品编号："+id + "商品剩余："+ stock.getNum() + "个！";
            }else {
                System.out.println("线程：" + threadId + ",商品编号："+id + ",商品库存不足！");
                return "线程：" + threadId + ",商品编号："+id + ",商品库存不足！";
            }
        }
        return "服务器正忙,请稍后再试.....";
    }

    /**
     * 2 忘了释放锁
     *
     * @param id id
     * @return {@link String}
     */
    @Override
    public String decrRedisReleaseLock(Integer id) {
        long threadId = Thread.currentThread().getId();
        Jedis jedis = new Jedis("127.0.0.1",6379);
        SetParams setParams = new SetParams();
        setParams.nx();
        setParams.px(200);
        String val = jedis.set("lockKey::" + id, "val", setParams);
        try {
            if ("OK".equals(val)) {
                RedisStock stock = redisStockDao.selectById(id);
                if(stock.getNum() > 0){
                    stock.setNum(stock.getNum() - 1);
                    redisStockDao.updateById(stock);
                    System.out.println("线程：" + threadId + ",商品编号："+id + ",商品剩余："+ stock.getNum() + "个！");
                    return "线程：" + threadId + ",商品编号："+id + "商品剩余："+ stock.getNum() + "个！";
                }else {
                    System.out.println("线程：" + threadId + ",商品编号："+id + ",商品库存不足！");
                    return "线程：" + threadId + ",商品编号："+id + ",商品库存不足！";
                }
            }
        }finally {
            jedis.del("lockKey::" + id);
        }
        return "服务器正忙,请稍后再试.....";
    }

    /**
     * 3 释放了别人的锁
     * 在释放锁的时候，先获取到该锁的值（之前设置值就是requestId），然后判断跟之前设置的值是否相同，
     * 如果相同才允许删除锁，返回成功。如果不同，则直接返回失败。
     *
     * 换句话说就是：自己只能释放自己加的锁，不允许释放别人加的锁。
     *
     * @param id id
     * @return {@link String}
     */
    @Override
    public String decrRedisReleaseLockOthers(Integer id) {
        long threadId = Thread.currentThread().getId();
        Jedis jedis = new Jedis("127.0.0.1",6379);
        SetParams setParams = new SetParams();
        setParams.nx();
        setParams.px(200);
        String val = jedis.set("lockKey::" + id, String.valueOf(threadId), setParams);
        if ("OK".equals(val)) {
            try {
                RedisStock stock = redisStockDao.selectById(id);
                if(stock.getNum() > 0){
                    stock.setNum(stock.getNum() - 1);
                    redisStockDao.updateById(stock);
                    System.out.println("线程：" + threadId + ",商品编号："+id + ",商品剩余："+ stock.getNum() + "个！");
                    return "线程：" + threadId + ",商品编号："+id + "商品剩余："+ stock.getNum() + "个！";
                }else {
                    System.out.println("线程：" + threadId + ",商品编号："+id + ",商品库存不足！");
                    return "线程：" + threadId + ",商品编号："+id + ",商品库存不足！";
                }
            }finally {
                if (jedis.get("lockKey::" + id).equals(String.valueOf(threadId))) {
                    jedis.del("lockKey::" + id);
                }
            }
        }
        return "服务器正忙,请稍后再试.....";
    }

    /**
     * 4 大量失败请求
     */
}
